Assignment 7: Image Enhancement

Tổng quan: Ở bài tập này, chúng ta sẽ thực hành lập trình một số hàm xử lí ảnh cơ bản

Yêu cầu thư viện: OpenCV 3.3, matplotlib

In [1]:
from IPython.display import Image

import matplotlib.pyplot as plt
import cv2
import numpy as np

I. Histograms, Histogram equalization

Biểu đồ Histogram của ảnh là một dạng biểu đồ biểu diễn sự phân bố của số lượng điểm ảnh tương ứng với mức độ sáng tối của bức ảnh.

  • Trong đó, trục dọc biểu diễn số lượng điểm ảnh, các đỉnh càng cao thì càng có nhiều điểm ảnh ở khu vực đó và độ chi tiết càng nhiều.
  • Trục ngang tính từ trái qua phải với mốc giá trị từ 0 đến 255 biểu diễn độ sáng của mỗi khu vực ảnh. Gốc giá trị 0 được coi là tối nhất tựa như màu đen tuyền trong khi càng dịch sang phải giá trị này càng tăng, ngọn sáng nhất của ánh sáng ở giá trị 255.

Để tính được Histogram của một ảnh, ta có thể dùng một trong các hàm sau:

In [2]:
img = cv2.imread('HoGuom.jpg', cv2.IMREAD_GRAYSCALE)
plt.imshow(img, cmap='gray')
Out[2]:
<matplotlib.image.AxesImage at 0x7f332a0672b0>
In [3]:
plt.hist(img.ravel(),256,[0,256]); plt.show()

Dựa vào Histogram có thể biết được bức ảnh là tối (dark) hay sáng (bright).

In [4]:
img = cv2.imread('dark.jpg', cv2.IMREAD_GRAYSCALE)
plt.subplot(211)
plt.imshow(img, cmap='gray')

plt.subplot(212)
plt.hist(img.ravel(),256,[0,256])
plt.show()
In [5]:
img = cv2.imread('bright.jpg', cv2.IMREAD_GRAYSCALE)
plt.subplot(211)
plt.imshow(img, cmap='gray')

plt.subplot(212)
plt.hist(img.ravel(),256,[0,256])
plt.show()

Đối với ảnh màu, ta có thể xem Histogram của từng kênh màu

In [6]:
Image('HoGuom.jpg')
Out[6]:
In [7]:
img = cv2.imread('HoGuom.jpg', cv2.IMREAD_COLOR)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img[:,:,[0,1]] = 0

plt.imshow(img)
Out[7]:
<matplotlib.image.AxesImage at 0x7f32f071c4e0>
In [8]:
img = cv2.imread('HoGuom.jpg', cv2.IMREAD_COLOR)
color = ('b','g','r')
for i,col in enumerate(color):
    histr = cv2.calcHist([img],[i],None,[256],[0,256])
    plt.plot(histr,color = col)
    plt.xlim([0,256])
plt.show()

Histogram Equalization

Thư viện OpenCV cung cấp hàm để Equalize Histogram:

In [9]:
Image('unequalized.jpg')
Out[9]:
In [10]:
img = cv2.imread('unequalized.jpg', cv2.IMREAD_GRAYSCALE)
equ = cv2.equalizeHist(img)
plt.imshow(equ, cmap='gray')
Out[10]:
<matplotlib.image.AxesImage at 0x7f32f06c55f8>
In [11]:
plt.subplot(211)
plt.hist(img.ravel(),256,[0,256])

plt.subplot(212)
plt.hist(equ.ravel(),256,[0,256])
plt.show()

Tuy nhiên không phải lúc nào Equalize Histogram toàn bộ ảnh cũng giúp đạt kết quả mong muốn

In [12]:
Image('statue_bright.jpg')
Out[12]:
In [13]:
img = cv2.imread('statue_bright.jpg', cv2.IMREAD_GRAYSCALE)
equ = cv2.equalizeHist(img)
plt.imshow(equ, cmap='gray')
Out[13]:
<matplotlib.image.AxesImage at 0x7f32f094dcf8>

CLAHE (Contrast Limited Adaptive Histogram Equalization)

Để giải quyết trường hợp này, ta cần dùng một phương pháp Histogram Equalization đặc biệt. Ảnh sẽ được chia thành các khối viên gạch "tiles" nhỏ (tileSize default của OpenCV là 8x8). Sau đó mỗi khối này được Equalize Histogram riêng. Nhờ đó histogram sẽ chỉ giới hạn trong một vùng nhỏ.

Thư viện OpenCV cung cấp hàm:

In [14]:
img = cv2.imread('statue_bright.jpg', cv2.IMREAD_GRAYSCALE)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
img = clahe.apply(img)
cv2.imwrite('newstatue.jpg', img)
Image('newstatue.jpg')
Out[14]:

Một số phép biến đổi Histogram theo từng pixel

Square transfrom

In [15]:
img = cv2.imread('HoGuom.jpg', cv2.IMREAD_GRAYSCALE)
for i in range(img.shape[0]):
    for j in range(img.shape[1]):
        img[i][j] = int(np.square(int(img[i][j]))/255)
plt.subplot(211)
plt.imshow(img, cmap='gray')

plt.subplot(212)
plt.hist(img.ravel(),256,[0,256])
plt.show()

Square root transfrom

In [16]:
img = cv2.imread('HoGuom.jpg', cv2.IMREAD_GRAYSCALE)
for i in range(img.shape[0]):
    for j in range(img.shape[1]):
        img[i][j] = int(np.sqrt(int(img[i][j])))
plt.subplot(211)
plt.imshow(img, cmap='gray')

plt.subplot(212)
plt.hist(img.ravel(),256,[0,256])
plt.show()

Các phép biến đổi pixel tổng quát

Convert Scale Absolute

\begin{align}{g(i,j) = \alpha \cdot f(i,j) + \beta} \end{align}

Các ham số α>0 và β có thể coi như là tham số điều chỉnh độ tương phản và độ sáng của ảnh.

cv2.convertScaleAbs(image, alpha=alpha, beta=beta) - https://docs.opencv.org/3.4/d2/de8/group__core__array.html#ga3460e9c9f37b563ab9dd550c4d8c4e7d

Gamma Correction

\begin{align}{O = \left( \frac{I}{255} \right)^{\gamma} \times 255} \end{align}

Với γ<1, các cùng ảnh ban đầu bị tối sẽ được tăng sáng và histogram sẽ có xu hướng dịch chuyển sang phải, ngược lại với γ>1, ảnh sẽ được giảm sáng.

gamma_correction(image, gamma=gamma)

In [17]:
Image('Gamma_Correction.png')
Out[17]:
In [18]:
def gamma_correction(img, gamma):
    for i in range(img.shape[0]):
        for j in range(img.shape[1]):
            img[i][j] = ((int(img[i][j])/255.0) ** gamma)*255
    return img
In [19]:
img = cv2.imread('HoGuom.jpg', cv2.IMREAD_GRAYSCALE)
img = gamma_correction(img, 2)
cv2.imwrite('gammaHoGuom.jpg', img)
Image('gammaHoGuom.jpg')
Out[19]:
In [20]:
img = cv2.imread('HoGuom.jpg', cv2.IMREAD_GRAYSCALE)
img = gamma_correction(img, 0.5)
cv2.imwrite('gammaHoGuom.jpg', img)
Image('gammaHoGuom.jpg')
Out[20]:

II. Image Filtering, Convolutions and Cross-correlations

cv2.filter2D - https://docs.opencv.org/2.4/modules/imgproc/doc/filtering.html#filter2d

In [21]:
Image('himym.jpg')
Out[21]:

Averaging kernel - Kernel lấy trung bình các điểm ảnh xung quanh

In [22]:
img = cv2.imread('himym.jpg', cv2.IMREAD_COLOR)
kernel = np.ones((5,5),np.float32)/25
img = cv2.filter2D(img, -1, kernel)
cv2.imwrite('newhimym.jpg', img)
Image('newhimym.jpg')
Out[22]:

Sharpening kernel - Kernel tăng độ nét của ảnh

In [23]:
img = cv2.imread('himym.jpg', cv2.IMREAD_COLOR)
kernel_sharpening = np.array([[-1,-1,-1], 
                              [-1, 9,-1],
                              [-1,-1,-1]])
img = cv2.filter2D(img, -1, kernel_sharpening)
cv2.imwrite('newhimym.jpg', img)
Image('newhimym.jpg')
Out[23]:

Blur, GaussiannBlur, medianBlur,...

Một số kernel đặc biệt dùng để làm mịn ảnh.

https://docs.opencv.org/2.4/modules/imgproc/doc/filtering.html#blur

In [24]:
img = cv2.imread('himym.jpg', cv2.IMREAD_COLOR)

# img = cv2.blur(img, (7, 7), 0)
# img = cv2.GaussianBlur(img, (9, 9), 0)
img = cv2.medianBlur(img, 9)

cv2.imwrite('newhimym.jpg', img)
Image('newhimym.jpg')
Out[24]:

Bài tập thực hành

Khử nhiễu và tăng chất lượng ảnh ở các bài tập sau

Bài tập 1: Noise Reduction

In [25]:
Image('deer_salt.jpg')
Out[25]:
In [26]:
img = cv2.imread('deer_salt.jpg', cv2.IMREAD_GRAYSCALE)

### YOUR CODE HERE ###

pass

### YOUR CODE HERE ###

cv2.imwrite('newdeer.jpg', img)
Image('newdeer.jpg')
Out[26]:
In [27]:
Image('needle1.png')
Out[27]:
In [28]:
img = cv2.imread('needle1.png', cv2.IMREAD_GRAYSCALE)

### YOUR CODE HERE ###

pass

### YOUR CODE HERE ###
            
cv2.imwrite('needle1_new.png', img)
Image('needle1_new.png')
Out[28]:

Bài tập 2: Image Enhancement

1. Moon

In [29]:
Image('moon_dark.jpg')
Out[29]:
In [30]:
img = cv2.imread('moon_dark.jpg', cv2.IMREAD_GRAYSCALE)

### YOUR CODE HERE ###

pass

### YOUR CODE HERE ###

cv2.imwrite('newmoon.jpg', img)
Image('newmoon.jpg')
Out[30]:

2. Balloon

In [31]:
Image('balloon.jpg')
Out[31]:
In [32]:
img = cv2.imread('balloon.jpg', cv2.IMREAD_GRAYSCALE)

### YOUR CODE HERE ###

pass

### YOUR CODE HERE ###

cv2.imwrite('newballoon.jpg', img)
Image('newballoon.jpg')
Out[32]:

3. Girl

In [33]:
Image('girl1_dark.jpg')
Out[33]:
In [34]:
img = cv2.imread('girl1_dark.jpg')
In [35]:
img = cv2.imread('girl1_dark.jpg')

### YOUR CODE HERE ###

pass

### YOUR CODE HERE ###

cv2.imwrite('newgirl1.jpg', img)
Image('newgirl1.jpg')
Out[35]:

BÀI TẬP VỀ NHÀ

Sử dụng các phương pháp cải thiện chất lượng ảnh đã học để cải thiện các ảnh trong thư mục homework. Đối với các trường hợp sử dụng cân bằng histogram, vẽ histogram của ảnh trước và sau khi áp dụng.

Khử nhiễu

In [36]:
Image('homework/noise.png')
Out[36]:
In [37]:
Image('homework/needle2.png')
Out[37]:

Cải thiện chất lượng

In [38]:
Image('homework/kid.png')
Out[38]:
In [39]:
Image('homework/hand.jpg')
Out[39]:

Tăng sáng

In [40]:
Image('homework/girl2_dark.jpg')
Out[40]:
In [41]:
Image('homework/mountain_dark.jpg')
Out[41]: